03. 函数定义-算术平均收益率计算

本章概要

  • 学习材料:一组同期收益率及其样本数。
  • 本章任务:定义算术平均函数,完成求和除以样本数,并与几何平均和中位数比较。
  • 完成后你将得到:函数返回值、手算总和/样本数和统计量选择说明。
  • 自我检查:用 sum(r)/len(r) 独立复算;空序列、缺失值或频率不一致时先检查原因。
  • 拓展练习:把函数拓展应用到另一指数同频收益率。

本章学习目标

  • 理解函数在金融编程中的核心作用
  • 掌握 deflambda 两种函数定义方式
  • 学会计算算术平均收益率
  • 了解算术平均与几何平均的区别
  • 能够编写带参数验证的健壮函数

函数:编程中的基本抽象单元

函数将一系列操作封装起来,使代码更加:

  • 模块化:每个函数专注做一件事
  • 可重用:一次编写,多次调用
  • 易维护:修改一处,全局生效

在金融计算中,收益率、波动率、VaR 等指标需要反复计算,函数是实现这一目标的关键工具。

函数体现的三种核心编程思想

函数体现的三种核心编程思想 展示抽象、分解、复用三个概念的示意图 抽象 Abstraction 隐藏实现细节 只暴露接口 🔒 分解 Decomposition 将复杂问题 分解为简单子问题 🧩 复用 Reuse 一次编写 多次调用 ♻️

算术平均收益率:最基本的金融指标

对于收益率序列 \(r_1, r_2, \ldots, r_n\),算术平均定义为:

\[ \large{ \bar{r} = \frac{1}{n} \sum_{i=1}^{n} r_i = \frac{r_1 + r_2 + \cdots + r_n}{n} } \]

金融含义:算术平均收益率适用于——

  • 单期期望收益率的估计
  • 投资组合绩效评估
  • 风险调整后收益率的基准

算术平均的关键数学性质

  • 线性性\(\overline{aX + bY} = a\bar{X} + b\bar{Y}\)
  • 最小二乘性:算术平均使误差平方和 \(\sum(x_i - \bar{x})^2\) 最小
  • 敏感性:对极端值敏感,受异常值影响大

易混淆概念:算术平均 vs. 几何平均

特性 算术平均 几何平均
公式 \(\bar{r}_A = \frac{1}{n}\sum r_i\) \(\bar{r}_G = [\prod(1+r_i)]^{1/n} - 1\)
应用场景 单期期望收益 多期复利增长
数值关系 \(\bar{r}_A \geq \bar{r}_G\) 波动率越大,差距越大
金融含义 期初财富的期望增长率 期末财富的实际增长率

关键理解:想知道”平均每期赚多少”→ 算术平均;计算”长期复利增长”→ 几何平均。

Python函数定义:def 关键字

def 是 Python 中最常用的函数定义方式:

def function_name(parameters):
    """文档字符串(Docstring)"""
    function_body
    return value
  • def:函数定义关键字
  • parameters:参数列表,多个参数用逗号分隔
  • return:返回值,无 return 则返回 None

def 定义算术平均函数

# 用def定义计算算术平均数的标准函数
def arithmetic_mean(numbers):
    """计算算术平均数"""
    return sum(numbers) / len(numbers)

# 测试函数
data = [1, 2, 3, 4, 5]
print(f'算术平均值: {arithmetic_mean(data)}')
算术平均值: 3.0
  • sum(numbers):计算列表元素总和
  • len(numbers):获取列表长度
  • /:执行浮点除法(Python 3 特性)

Python函数定义:lambda 表达式

lambda 用于定义匿名函数,适合简单的单行函数:

# 语法格式
lambda parameters: expression
# lambda定义算术平均函数
arithmetic_mean_lambda = lambda x: sum(x) / len(x)

data = [1, 2, 3, 4, 5]
print(f'lambda计算结果: {arithmetic_mean_lambda(data)}')
lambda计算结果: 3.0

lambda 的限制:只能包含单个表达式,不能包含语句(如 ifforwhile)。

def vs. lambda:如何选择?

def与lambda的对比 展示def和lambda两种函数定义方式的适用场景对比 def 标准函数 ✅ 可包含多条语句 ✅ 支持文档字符串 ✅ 可复杂逻辑与异常处理 ✅ 可读性强,便于调试 适合:复杂逻辑、生产代码 lambda 匿名函数 ⚡ 仅支持单个表达式 ⚡ 无文档字符串 ⚡ 代码简洁紧凑 ⚡ 常配合 map/filter 使用 适合:简单计算、临时函数

运行前预测|平台任务:计算上证指数算术平均收益率

  • 输入预测:运行前先写出 A_meansh000001 的业务含义、数据类型或取值范围,并判断哪一个输入最可能改变结果。
  • 结果预测:不展开答案,先预测将得到sh000001 的结果;同时写出方向、数量级或表格/图形结构。
  • 完成要求:能独立说明本任务从输入到“平台任务:计算上证指数算术平均收益率”结果的关键步骤,原样录入平台代码并得到可核对的运行结果。

⭐ 平台任务:计算上证指数算术平均收益率

# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
A_mean=lambda x:sum(x)/len(x)  # 定义匿名函数A_mean
sh000001=[26.468,-10.7081,2.8477,43.5348,13.4337]  # 定义列表sh000001
print(round(A_mean(sh000001),2))  # 输出四舍五入后的计算结果

任务复盘|平台任务:计算上证指数算术平均收益率

运行后核对:核对 A_meansh000001 是否按预测参与运算,实际输出是否与预测一致;若不一致,先检查类型、单位、索引/字段和运算顺序。

拓展练习:把对象或期间改为一家长三角上市公司或一组 A 股资产;先预测指标方向,再说明结果能支持和不能支持的决策。

平台代码逐步解析

步骤 关键表达式 可核对结果
定义函数 lambda x: sum(x)/len(x) 输入列表,输出均值
准备数据 sh000001 5个无来源的平台注册输入(百分数)
计算输出 round(A_mean(...), 2) 15.12

核对:\(75.5762\div5=15.11524\rightarrow15.12\)

平台示例数据只说明算术平均的计算

15.12% 只是平台固定输入的样本算术均值;缺少来源、年份、频率和复权口径,不能把它当作上证指数事实或前瞻期望。

  • 算术均值:描述单期输入的平均水平
  • 几何收益:回答同一财富路径的复合增长;仅当每期 r_i > -1 时定义
  • 风险边界:还需报告波动、样本期、极端值与不确定性,才能讨论投资含义

扩展:带参数验证的函数

def calculate_mean_return(returns, decimals=2):
    """
    计算算术平均收益率
    参数:
        returns (list): 收益率序列
        decimals (int): 保留小数位数,默认为2
    """
    # 参数验证:检查输入有效性
    if not returns:
        raise ValueError('收益率列表不能为空')
    if not all(isinstance(r, (int, float)) for r in returns):
        raise ValueError('收益率必须为数值类型')
    # 计算并返回
    mean = sum(returns) / len(returns)
    return round(mean, decimals)

# 使用示例
sh000001 = [26.468, -10.7081, 2.8477, 43.5348, 13.4337]
result = calculate_mean_return(sh000001, decimals=3)
print(f'上证指数平均收益率: {result:.3f}%')
上证指数平均收益率: 15.115%

生产级函数的三个关键要素

  1. 文档字符串:写清功能、参数、返回值与单位。
  2. 参数验证:在入口处拒绝空值、错误类型与越界输入。
  3. 默认参数:只为稳定且可解释的选择提供默认值,例如 decimals=2

课后扩展:配合 map 批量计算

# 投资组合中各股票的收益率
portfolio_returns = {
    'Stock A': [0.05, 0.03, -0.02, 0.04, 0.06],
    'Stock B': [0.08, 0.02, 0.01, -0.03, 0.05],
    'Stock C': [-0.01, 0.04, 0.07, 0.02, 0.03]
}

# 用lambda + map批量计算每只股票的平均收益率
mean_calculator = lambda returns: round(sum(returns) / len(returns), 4)
mean_returns = list(map(mean_calculator, portfolio_returns.values()))

for name, mean_r in zip(portfolio_returns.keys(), mean_returns):
    print(f'{name} 平均收益率: {mean_r}')
Stock A 平均收益率: 0.032
Stock B 平均收益率: 0.026
Stock C 平均收益率: 0.03

课后扩展:配合 filter 筛选数据

# 使用filter筛选正收益
returns_data = [0.05, -0.02, 0.03, -0.01, 0.08, -0.04]

positive_returns = list(filter(lambda r: r > 0, returns_data))
negative_returns = list(filter(lambda r: r < 0, returns_data))

print(f'正收益: {positive_returns}')
print(f'负收益: {negative_returns}')
print(f'胜率: {len(positive_returns)/len(returns_data):.1%}')
正收益: [0.05, 0.03, 0.08]
负收益: [-0.02, -0.01, -0.04]
胜率: 50.0%
  • filter(function, iterable) 根据条件筛选元素
  • 在金融中可用于筛选盈利交易、亏损交易等

课后扩展:配合 reduce 计算累积收益

展开实现代码
from functools import reduce

# 计算累积收益率(复利效果)
returns = [0.05, 0.03, -0.02, 0.04]

# reduce逐步累积:1 → 1*(1+0.05) → 1.05*(1+0.03) → ...
cumulative_return = reduce(lambda x, y: x * (1 + y), returns, 1) - 1

print(f'各期收益率: {returns}')
print(f'算术平均收益率: {sum(returns)/len(returns):.4f}')
print(f'累积收益率: {cumulative_return:.4f}')
各期收益率: [0.05, 0.03, -0.02, 0.04]
算术平均收益率: 0.0250
累积收益率: 0.1023
  • reduce 对序列进行累积计算
  • 初始值 1 代表初始本金
  • 最终结果减 1 得到净收益率

算术平均的局限性

算术平均虽然简单直观,但在金融应用中存在重要局限:

  1. 极端值敏感:一个极端值会显著拉高/拉低平均值
  2. 不适用于多期增长:会高估长期复利增长
  3. 分布假设:隐含假设收益率对称分布,但实际金融收益常呈偏态分布

改进方案:稳健统计量

展开实现代码
import numpy as np
from scipy import stats

# 包含极端值的收益率数据
returns = [0.05, 0.03, 0.04, 0.50, 0.02, -0.10, 0.06]

# 四种集中趋势度量的比较
arithmetic_mean = np.mean(returns)
median = np.median(returns)
trimmed_mean = stats.trim_mean(returns, 0.1)
winsorized_mean = stats.mstats.winsorize(
    np.array(returns), limits=[0.1, 0.1]
).mean()

print(f'算术平均: {arithmetic_mean:.4f}')
print(f'中位数:   {median:.4f}')
print(f'截尾平均: {trimmed_mean:.4f}')
print(f'缩尾平均: {winsorized_mean:.4f}')
算术平均: 0.0857
中位数:   0.0400
截尾平均: 0.0857
缩尾平均: 0.0857

如何选择合适的统计量?

场景 推荐统计量 理由
独立同分布且均值有限的同频样本 算术平均 对总体均值无偏;正态同方差模型下还具有效率性质
含极端值 中位数/截尾平均 稳健性强
投资组合基准 算术平均 与 CAPM 模型一致
长期绩效评估 几何平均 反映真实复利增长

本章总结

  • 函数定义def(复杂逻辑)vs. lambda(简单计算)
  • 算术平均\(\bar{r} = \frac{1}{n}\sum r_i\),适用于单期期望收益估计
  • 高阶函数map(批量计算)、filter(筛选)、reduce(累积)
  • 稳健统计:面对极端值时,考虑中位数或截尾平均
  • 最佳实践:生产代码应包含文档字符串和参数验证

随堂练习

  • 问题 1|需要准备哪些数据?:一组同期收益率及其样本数。
  • 问题 2|需要完成哪些操作?:定义算术平均函数,完成求和除以样本数,并与几何平均和中位数比较。
  • 问题 3|应得到哪些结果?:函数返回值、手算总和/样本数和统计量选择说明。
  • 问题 4|怎样确认结果可靠?:用 sum(r)/len(r) 独立复算;空序列、缺失值或频率不一致时先检查原因。
  • 问题 5|换一个情境,怎样继续应用?:把函数拓展应用到另一指数同频收益率。
  • 作答提示:请依次写清所用数据、分析过程、所得结果、核对方法和拓展思考。课程所需数据见前言中的下载入口;教学平台固定题按页面说明完成。

教师参考解答|答案与说明 1

  • 逐项答案:下方代码完成平台函数的输入、求和、除以样本数与格式化输出;函数通过稳定参数/返回值支持复用,但空列表会除零;拓展应用到长三角股票时替换为同频简单收益,并用 sum/n 与中位数双重核对,财富增长另用连乘。

  • 所用数据与字段:简单收益率列表,单位为小数

  • 参考代码或推导(平台保护块之外):

教师参考解答|代码 1

展开代码(代码区可独立滚动)
returns=[0.05,-0.02,0.03]  # 定义三期收益率
answer=sum(returns)/len(returns)  # 计算算术平均
print(f'{answer:.4f}')  # 输出四位小数

教师参考解答|答案与说明 2

  • 参考结果:0.0200;推导为 (0.05-0.02+0.03)/3
  • 边界 / 局限:多期财富增长使用连乘
  • 常见错误:空列表除零;百分数与小数混用